#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

from abc import ABC, abstractmethod
from typing import Optional, Union

from common.const import ExecuteResultEnum
from common.const import RpcToolInterface
from common.schemas.thrift_base_data_type import (ActionResult, SubJob, ExecutePolicy, SubJobType, Copy,
                                                  CopyDataTypeEnum)
from common.schemas.thrift_framework import SubJobStatus, SubJobDetails
from common.schemas.thrift_plugin import BackupJob, JobResult, Application
from saporacle.comm.common_util import rpctool_api
from saporacle.comm.logger import logger
from saporacle.comm.saporacle_exception import SAPOracleException
from saporacle.backup.data_backup_saporacle import DataBackupSAPOracle
from saporacle.comm.datamodels import QueryPreviousCopyParam
from saporacle.backup.log_backup_saporacle import LogBackupSAPOracle
from saporacle.comm.repository import Repository


class SAPOracleBackupService(ABC):

    def __init__(self, pid: str, saporacle: Union[DataBackupSAPOracle, LogBackupSAPOracle],
                 repository: Optional[Repository]) -> None:
        self._pid = pid
        self._saporacle = saporacle
        self._repository = repository

    def check_backup_job_type(self, backup_job: BackupJob) -> ActionResult:
        result = ActionResult(code=ExecuteResultEnum.SUCCESS)
        return result

    def allow_backup_in_local_node(self, backup_job: BackupJob) -> ActionResult:
        try:
            self._saporacle.login()
            self._saporacle.user_has_sufficient_privilege()
        except SAPOracleException as e:
            logger.error(f"Not allow backup in local node. {e}")
            return ActionResult(code=ExecuteResultEnum.INTERNAL_ERROR, bodyErr=e.err_code, bodyErrParams=e.parameters)
        logger.info("Allow backup in local node.")
        return ActionResult(code=ExecuteResultEnum.SUCCESS)

    @abstractmethod
    def backup_prerequisite(self, backup_job: BackupJob) -> None:
        pass

    def backup_gen_sub_job(self, backup_job: BackupJob) -> list[SubJob]:
        sub_jobs = [
            SubJob(jobId=backup_job.job_id, jobType=SubJobType.BUSINESS_SUB_JOB, jobName=self.prepare_sub_job.__name__,
                   policy=ExecutePolicy.ANY_NODE, jobPriority=1),
            SubJob(jobId=backup_job.job_id, jobType=SubJobType.BUSINESS_SUB_JOB, jobName=self.backup_sub_job.__name__,
                   policy=ExecutePolicy.ANY_NODE, jobPriority=2)
        ]
        return sub_jobs

    def backup(self, backup_job: BackupJob, sub_job: SubJob) -> None:
        getattr(self, sub_job.job_name)(backup_job, sub_job)

    def backup_post_job(self, job_result: JobResult, backup_job: BackupJob, sub_job: SubJob) -> None:
        try:
            self._saporacle.dump_brtools_outfile()
            self._saporacle.remove_backint_param_file()
            self._repository.remove_cache_dir()
            job_result != JobResult.SUCCESS and self._repository.remove_data_dir()
        except SAPOracleException as e:
            logger.error(f"Backup post job failed. {e}")
            job_details = SubJobDetails(taskId=backup_job.job_id, subTaskId=sub_job.sub_job_id,
                                        taskStatus=SubJobStatus.FAILED_NOTRY)
            rpctool_api(self._pid, RpcToolInterface.REPORT_JOB_DETAIL, job_details.dict(by_alias=True))
            return
        logger.info("Backup post job succeeded.")
        job_details = SubJobDetails(taskId=backup_job.job_id, subTaskId=sub_job.sub_job_id,
                                    taskStatus=SubJobStatus.COMPLETED)
        rpctool_api(self._pid, RpcToolInterface.REPORT_JOB_DETAIL, job_details.dict(by_alias=True))

    @abstractmethod
    def pause_job(self, backup_job: BackupJob, sub_job: SubJob) -> ActionResult:
        pass

    """自定义备份子任务"""

    @abstractmethod
    def prepare_sub_job(self, backup_job: BackupJob, sub_job: SubJob) -> None:
        pass

    @abstractmethod
    def backup_sub_job(self, backup_job: BackupJob, sub_job: SubJob) -> None:
        pass

    """private"""

    def _query_previous_copy(self, application: Application, types: list[CopyDataTypeEnum], copy_id: str
                             ) -> Optional[Copy]:
        """
        :raise SAPOracleException:
        """
        param = QueryPreviousCopyParam(application=application, types=types, copyId=copy_id)
        result = rpctool_api(self._pid, RpcToolInterface.QUERY_PREVIOUS_COPY, param.dict(by_alias=True))
        if not result:
            logger.info(f"Query previous copy. {list(map(str, types))} -> None")
            return None
        _copy = Copy(**result)
        logger.info(f"Query previous copy. {list(map(str, types))} -> {_copy.id} {_copy.type}")
        return _copy
